﻿using System.ComponentModel.Composition;
using System.Linq;
using Cubicle.Core.Interfaces;
using Cubicle.Core.Processors.Parameter;

namespace Cubicle.Core.Processors.Invoke
{
    [Export("Cubicle.Processors.Invoke.GetPropertyProcessor", typeof(IProcessor<InstructionRequest>))]
    [ExportMetadata("Name", "GetPropertyProcessor")]
    [ExportMetadata("Description", "Performs a 'get' operation on a property")]
    public class GetPropertyProcessor : InstructionRequestProcessor
    {

        [Import]
        private ParameterProcessor _paramProcessor;

        [ImportingConstructor]
        public GetPropertyProcessor() : base(RequestType.Virtual | RequestType.Static | RequestType.Property | RequestType.Get) { }

        #region Overrides of Processor<InstructionRequest>

        public override InstructionRequest ConditionalProcess(InstructionRequest request)
        {
            if (request.TargetProperty == null)
            {
                request.Fail("No property to get.");
                return request;
            }

            var parameters = request.Inst.Parameters;
            var indexers = request.TargetProperty.GetIndexParameters();

            // Don't fail here - this could be a property Set operation.
            if (parameters != null && indexers.Length != parameters.Length)
                return request;

            // Resolve
            object[] resolvedIndexes = null;
            if (parameters != null && parameters.Length > 0 && indexers.Length > 0)
                resolvedIndexes = indexers
                    .Select(x => x.ParameterType)
                    .ToArray()
                    .Process<object>(parameters, _paramProcessor);

            // Before accessor event
            var args = new InstructionEventArgs(InstructionEventType.BeforeAccessor, request);
            RaiseProcessorEvent(this, args);

            var result = request.TargetProperty.GetValue(request.Target, resolvedIndexes);

            // After accessor event
            args = new InstructionEventArgs(InstructionEventType.AfterAccessor, request);
            RaiseProcessorEvent(this, args);

            request.Complete(result);
            return request;
        }

        #endregion
    }
}